#include "data.hpp"
#include "httplib.h"

namespace vod
{
#define WWWROOT "./www"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"

    TableVideo *tb_video = nullptr;

    class Server
    {
    public:
        Server(int port) : port_(port) {}
        // 启动服务器
        bool RunModule()
        {
            // 1.初始化, 初始化数据管理模块, 创建指定的目录
            tb_video = new TableVideo();
            FileUtil(WWWROOT).CreateDirectory();
            // 初始路径
            std::string root = WWWROOT;
            // 视频路径
            std::string video_real_path = root + VIDEO_ROOT;
            FileUtil(video_real_path).CreateDirectory();
            // 图片路径
            std::string image_real_path = root + IMAGE_ROOT;
            FileUtil(image_real_path).CreateDirectory();
            // 2.搭建http服务器, 开始运行
            // 2.1 设置静态资源根目录
            srv_.set_mount_point("/", WWWROOT);
            // 2.2 添加请求, 处理函数映射关系
            // 使用正则表达式\d+, \为转义字符, \\表示单反斜杠
            srv_.Post("/video", Insert);
            srv_.Delete("/video/(\\d+)", Delete);
            srv_.Put("/video/(\\d+)", Update);
            srv_.Get("/video/(\\d+)", SelectOne);
            srv_.Get("/video", SelectAll);
            // 3. 启动服务器
            srv_.listen("0.0.0.0", port_);
            return true;
        }
    private:
        // 插入视频
        static void Insert(const httplib::Request &req, httplib::Response &rsp)
        {
            // 插入的视频不满足条件
            if(req.has_file("name") == false ||
               req.has_file("info") == false ||
               req.has_file("video") == false ||
               req.has_file("image") == false)
            {
                rsp.status = 400;
                // 原始字符串字面量R, 防止对字符转义
                rsp.body = R"({"result":false, "reason":"上传的数据信息错误"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 获取表单
            httplib::MultipartFormData name = req.get_file_value("name");   // 视频名称
            httplib::MultipartFormData info = req.get_file_value("info");   // 视频简介
            httplib::MultipartFormData video = req.get_file_value("video"); // 视频文件
            httplib::MultipartFormData image = req.get_file_value("image"); // 图片文件

            // 获取视频名称
            std::string video_name = name.content;
            // 获取视频简介
            std::string video_info = info.content;

            // 初始路径
            std::string root = WWWROOT;
            // 视频路径
            std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
            // 图片路径
            std::string image_path = root + IMAGE_ROOT + video_name + image.filename;

            // 添加视频
            if(FileUtil(video_path).SetContent(video.content) == false)
            {
                // 添加视频失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result": false, "reason":"视频文件存储失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 添加图片
            if(FileUtil(image_path).SetContent(image.content) == false)
            {
                // 添加图片失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result": false, "reason":"图片文件存储失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            Json::Value video_json;
            video_json["name"] = video_name;
            video_json["info"] = video_info;
            video_json["video"] = VIDEO_ROOT + video_name + video.filename;
            video_json["image"] = IMAGE_ROOT + video_name + image.filename;
            // 插入视频失败, 返回失败响应
            if(tb_video->Insert(video_json) == false)
            {
                // 插入视频失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result": false, "reason":"数据库新增数据失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            rsp.set_redirect("/index.html", 303);
            return;
        }

        // 更新视频信息
        static void Update(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 获取要修改的视频信息(matches[1]:视频id matches[2]: 修改后的信息)
            // matches[1]拿到要修改的视频id
            int video_id = std::stoi(req.matches[1]);
            Json::Value video;
            // 反序列化
            if(JsonUtil::UnSerialize(req.body, &video) == false)
            {
                // 反序列化失败, 返回失败响应
                rsp.status = 400;
                rsp.body = R"({"result": false, "reason":"新的视频信息格式解析失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 2. 更新数据库数据
            if(tb_video->Update(video_id, video) == false)
            {
                // 修改失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result": false, "reason":"更新数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            return;
        }

        // 删除视频
        static void Delete(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 获取要删除的视频ID
            int video_id = std::stoi(req.matches[1]);
            // 2. 删除视频以及图片文件
            Json::Value video;
            // 查询要删除的视频
            if(tb_video->SelectOne(video_id, &video) == false)
            {
                // 查询视频失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"不存在视频信息"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            std::string root = WWWROOT;
            std::string video_path = root + video["video"].asString();
            std::string image_path = root + video["image"].asString();
            // 删除视频
            remove(video_path.c_str());
            // 删除图片
            remove(image_path.c_str());
            // 3.删除数据库信息
            if(tb_video->Delete(video_id) == false)
            {
                // 删除视频失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result": false, "reason":"删除数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            return;
        }

        // 查询单个视频
        static void SelectOne(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 获取视频的ID
            int video_id = std::stoi(req.matches[1]);
            // 2. 在数据库中查询指定视频信息
            Json::Value video;
            if(tb_video->SelectOne(video_id, &video) == false)
            {
                // 查询视频失败, 返回失败响应
                rsp.status = 500;
                rsp.body = R"({"result": false, "reason":"查询数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 3. 组织响应正文(json格式的字符串)
            JsonUtil::Serialize(video, &rsp.body);
            rsp.set_header("Content-Type", "application/json");
            return;
        }
        
        // 查询所有视频, 以及模糊查询
        // SelectAll这里包括SelectLike
        static void SelectAll(const httplib::Request &req, httplib::Response &rsp)
        {
            // 默认All查询
            bool select_flag = true;
            std::string search_key;
            if(req.has_param("search") == true)
            {
                // 模糊匹配Like
                select_flag = false;
                search_key = req.get_param_value("search");
            }
            Json::Value videos;
            if(select_flag == true)
            {
                // 查询所有视频
                if(tb_video->SelectAll(&videos) == false)
                {
                    // 查询所有视频失败, 返回失败响应
                    rsp.status = 500;
                    rsp.body = R"({"result": false, "reason":"查询数据库指定视频信息失败"})";
                    rsp.set_header("Content-Type", "application/json");
                    return;
                }
            }
            else
            {
                // 模糊查询
                if(tb_video->SelectLike(search_key, &videos) == false)
                {
                    // 模糊视频失败, 返回失败响应
                    rsp.status = 500;
                    rsp.body = R"({"result": false, "reason":"查询数据库匹配视频信息失败"})";
                    rsp.set_header("Content-Type", "application/json");
                    return;
                }
            }

            // 3. 组织响应正文(json格式的字符串)
            JsonUtil::Serialize(videos, &rsp.body);
            rsp.set_header("Content-Type", "application/json");
            return;
        }
    private:
        int port_;            // 端口号
        httplib::Server srv_; // httplib服务
    };
}